package bg.cinema_system.beans;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;

import bg.cinema_system.service.MailService;
import bg.cinema_system.service.ProjectionService;
import bg.cinema_system.service.ReservationService;
import bg.cinema_system.utils.Constants;
import bg.cinema_system.utils.MathOperations;

@ManagedBean(name = "reservation")
@RequestScoped
public class ReservationBean extends BaseBean {
	
	private static final long serialVersionUID = 7865012326886933572L;
	private Set<Integer> unavailableSeats;
	private int projectionId;
	private MovieBean movie;
	private int hallNumber;
	private String movieStartTime;
	private Boolean[] seats;
	private Boolean[] seatsInitialState;

	public ReservationBean() throws SQLException {
		super();
		setProjectionId();
		setUnavailableSeats();
		setMovie();
		setHallNumber();
		setMovieStartTime();
		initializeSeats();	
	}
	
	public Boolean[] getSeats() {
		return seats;
	}

	public void initializeSeats() {
		this.seats = new Boolean[Constants.NUMBER_HALL_SEATS];
		this.seatsInitialState = new Boolean[Constants.NUMBER_HALL_SEATS];
		
		for (int i=0; i < this.seats.length; i++) {
			
			if (this.unavailableSeats.contains(new Integer(i+1))) {
				this.seats[i] = true;
				this.seatsInitialState[i] = true;
			} else {
				this.seats[i] = false;
				this.seatsInitialState[i] = false;
			}
		}
	}
	
	public String getMovieStartTime() {
		return movieStartTime;
	}

	public void setMovieStartTime() throws SQLException {
		SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
		String movieStartTime = sdf.format(ProjectionService.getMovieStartTime(this.projectionId));
		this.movieStartTime = movieStartTime;
	}
	
	public MovieBean getMovie() {
		return movie;
	}

	public void setMovie() throws SQLException {
		MovieBean movie = ProjectionService.getMovie(this.projectionId);
		this.movie = movie;
	}

	public int getHallNumber() {
		return hallNumber;
	}

	public void setHallNumber() throws SQLException {
		int hallNumberProjection = ProjectionService.getHallNumber(this.projectionId);
		this.hallNumber = hallNumberProjection;
	}

	public Set<Integer> getUnavailableSeats() throws SQLException {
		return unavailableSeats;
	}

	public void setUnavailableSeats() throws SQLException {
		List<Integer> reservedSeats = ReservationService.getReservedSeats(this.projectionId);
		List<Integer> paidSeats = ReservationService.getPaidSeats(this.projectionId);
		
		this.unavailableSeats = MathOperations.getMerged(reservedSeats, paidSeats);
	}

	public int getProjectionId() {
		return projectionId;
	}

	public void setProjectionId() {
		HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
		String projectionIdString = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("projection_id");
		
		if (projectionIdString != null) {
			this.projectionId = Integer.parseInt(projectionIdString);
			session.setAttribute("projectionId", this.projectionId);
		} else {
			this.projectionId = (Integer) session.getAttribute("projectionId");
		}
	}
	
	public String reserve() throws SQLException {
		List<Integer> reservedSeats = new ArrayList<Integer>();
		
		for (int i=0; i < seats.length; i++) {
			if (seats[i] == true && seatsInitialState[i] == false) {
				reservedSeats.add(i+1);
			}
		}
		
		if (!reservedSeats.isEmpty()) {
			int userId = (Integer) getSession().getAttribute("userId");
			
			Date projectionDate = ProjectionService.getMovieStartTime(this.projectionId);
			Date expDate = MathOperations.addMinutes(projectionDate, (-1)*Constants.EXPIRE_BEFORE_PROJECTION);
			
			ReservationService.makeReservation(reservedSeats, this.projectionId, userId, expDate);
			MailService ms = new MailService();
			ms.sendEmailTo(userId, movie.getName(), projectionDate, reservedSeats);
		}
		
		return "user_daily_program";
	}
	
}
